02. Java Persistence API (JPA)

JavaND#305 C03 L02 A02 JPA Introduction

JPA Entities

Entities

An entity is a lightweight persistence domain object. Typically, an entity represents a table in a relational database, and each entity instance corresponds to a row in that table. The primary programming artifact of an entity is the entity class, although entities can use helper classes.

The persistent state of an entity is represented through either persistent fields or persistent properties. These fields or properties use object/relational mapping annotations to map the entities and entity relationships to the relational data in the underlying data store.

Requirements for Entity Classes

An entity class must follow these requirements.

The class must be annotated with the javax.persistence.Entity annotation.
The class must have a public or protected, no-argument constructor. The class may have other constructors.
The class must not be declared final. No methods or persistent instance variables must be declared final.
Entities may extend both entity and non-entity classes, and non-entity classes may extend entity classes.
Persistent instance variables must be declared private, protected, or package-private and can be accessed directly only by the entity class’s methods. Clients must access the entity’s state through accessor or business methods.

Persistent Fields

If the entity class uses persistent fields, the Persistence runtime accesses entity-class instance variables directly. All fields not annotated javax.persistence.Transient or not marked as Java transient will be persisted to the data store. The object/relational mapping annotations must be applied to the instance variables.

Primary Keys in Entities

Each entity has a unique object identifier. A customer entity, for example, might be identified by a customer number. The unique identifier, or primary key, enables clients to locate a particular entity instance. Every entity must have a primary key. An entity may have either a simple or a composite primary key.
Simple primary keys use the javax.persistence.Id annotation to denote the primary key property or field.

The primary key, or the property or field of a composite primary key, must be one of the following Java language types:
Java primitive types
Java primitive wrapper types
java.lang.String
java.util.Date
java.sql.Date
java.math.BigDecimal
java.math.BigInteger

Floating-point types should never be used in primary keys.

Generated Identifiers

Primary key values can be automatically generated using the @GeneratedValue annotation.

It supports four generation strategies,
AUTO
IDENTITY
SEQUENCE
TABLE

If a value is not specified for the strategy field of the annotation, the default is AUTO.

AUTO Generation

For the default generation type, the persistence provider will determine values based on the type of the primary key attribute. For numeric values, the generation is based on a sequence or table generator.

Let’s see an example of mapping an entity primary key using AUTO generation strategy:

@Entity
public class Order {

    @Id
    @GeneratedValue
    private Long orderId;

}

In this case, the primary key values will be unique at the database level.

IDENTITY Generation

This type of generation relies on the IdentityGenerator which expects values generated by an identity column in the database, meaning they are auto-incremented. If a primary column is set as AUTO_INCREMENT in the table, this strategy can be used.

To use this generation type, we only need to set the strategy parameter:

@Entity
public class Order {

    @Id
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private long orderId;

}
SEQUENCE Generation

This generator uses sequences if supported by the database or switches to table generation if it doesn’t.

To customize the sequence name, we can use the @GenericGenerator annotation with
SequenceStyleGenerator strategy:

@Entity
public class Order {
    @Id
    @GeneratedValue(generator = "sequence-generator")
    @GenericGenerator(
      name = "sequence-generator",
      strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
      parameters = {
        @Parameter(name = "sequence_name", value = "user_sequence"),
        @Parameter(name = "initial_value", value = "4"),
        @Parameter(name = "increment_size", value = "1")
        }
    )
    private Long orderId;


}

In this example, an initial value is set for the sequence, which means the primary key generation will start at 4. The generated values are unique per sequence. If a sequence name is not specified, Hibernate will re-use the same hibernate_sequence for different types.

TABLE Generation

The TableGenerator uses an underlying database table that holds segments of identifier generation values.
Let’s customize the table name using the @TableGenerator annotation,

@Entity
public class Order {
    @Id
    @GeneratedValue(strategy = GenerationType.TABLE,
      generator = "table-generator")
    @TableGenerator(name = "table-generator",
      table = "dep_ids",
      pkColumnName = "seq_id",
      valueColumnName = "seq_value")
    private Long orderId;

}

In this example, we can see that other attributes such as the pkColumnName and valueColumnName can also be customized.

All of the four generation types will generate similar values but use different database mechanisms to do so.

JPA Quiz

What are the requirements for a class to become an entity? Check all that apply.

SOLUTION:
  • The class must be annotated with the _javax.persistence.Entity_ annotation.
  • The class must have a public or protected, no-argument constructor.

JPA Quiz

How to exclude a field in the entity class from persistence?

SOLUTION: The field should be annotated with @Transient.

JPA Quiz

What is the generation strategy to be used when the primary key is set to AUTO_INCREMENT?

SOLUTION: IDENTITY

Javand305-C03-L02-A03-Entity-Relationships

Entity Relationships

Relationships are of the following types: one-to-one, one-to-many, many-to-one, and many-to-many:

One-to-one: Each entity instance is related to a single instance of another entity. For example, to model a sales order, Order and Address would have a one-to-one relationship. One-to-one relationships use the javax.persistence.OneToOne annotation on the corresponding persistent property or field.

One-to-many: An entity instance can be related to multiple instances of the other entities. A sales order, for example, can have multiple order items. In the order application, Order would have a one-to-many relationship with OrderItem. One-to-many relationships use the javax.persistence.OneToMany annotation on the corresponding persistent property or field.

Many-to-one: Multiple instances of an entity can be related to a single instance of the other entity. This multiplicity is the opposite of a one-to-many relationship. In the example just mentioned, the relationship to Order from the perspective of OrderItem is many-to-one. Many-to-one relationships use the javax.persistence.ManyToOne annotation on the corresponding persistent property or field.

Many-to-many: The entity instances can be related to multiple instances of each other. For example, each college course has many students, and every student may take several courses. Therefore, in an enrollment application, Course and Student would have a many-to-many relationship. Many-to-many relationships use the javax.persistence.ManyToMany annotation on the corresponding persistent property or field.

Direction in Entity Relationships

The direction of a relationship can be either bidirectional or unidirectional. A bidirectional relationship has both an owning side and an inverse side. A unidirectional relationship has only an owning side. The owning side of a relationship determines how the Persistence runtime makes updates to the relationship in the database.

Bidirectional Relationships

In a bidirectional relationship, each entity has a relationship field or property that refers to the other entity. Through the relationship field or property, an entity class’s code can access its related object. If an entity has a related field, the entity is said to “know” about its related object. For example, if Order knows what OrderItem instances it has and if OrderItem knows what Order it belongs to, they have a bidirectional relationship.
Bidirectional relationships must follow these rules.
The inverse side of a bidirectional relationship must refer to its owning side by using the mappedBy element of the @OneToOne, @OneToMany, or @ManyToMany annotation. The mappedBy element designates the property or field in the entity that is the owner of the relationship.
The many side of many-to-one bidirectional relationships must not define the mappedBy element. The many side is always the owning side of the relationship.
For one-to-one bidirectional relationships, the owning side corresponds to the side that contains the corresponding foreign key.
For many-to-many bidirectional relationships, either side may be the owning side.

Unidirectional Relationships

In a unidirectional relationship, only one entity has a relationship field or property that refers to the other. For example, OrderItem would have a relationship field that identifies Product, but Product would not have a relationship field or property for OrderItem. In other words, OrderItem knows about Product, but Product doesn’t know which OrderItem instances refer to it.

Quiz

How to map a bi-directional One-to-Many relationship?

SOLUTION: One-to-Many and Many-to-one on both sides of the relationship. Owning side includes the foreign key and the inverse side includes the mappedBy field of the owning entity.

Quiz

Which of these statements is true for a Many-to-Many relationship?

SOLUTION: Many-to-Many requires a mapping table.

Exercise

Task Description:

Students will be provided starter code that connects to a MySQL database.
Students will write code using simple EntityManager methods persist() and find().

Task List:

Task Feedback:

Nicely done.

JavaND#305 C03 L02 A04 Cascade & Fetch

Cascade Details

Cascade Operations and Relationships

Entities that use relationships often have dependencies on the existence of the other entity in the relationship. For example, a line item is part of an order; if the order is deleted, the order item also should be deleted. This is called a cascade delete relationship.

The javax.persistence.CascadeType enumerated type defines the cascade operations that are applied in the cascade element of the relationship annotations.

ALL: All cascade operations will be applied to the parent entity’s related entity. All is equivalent to specifying cascade={DETACH, MERGE, PERSIST, REFRESH, REMOVE}.
DETACH: If the parent entity is detached from the persistence context, the related entity will also be detached.
MERGE: If the parent entity is merged into the persistence context, the related entity will also be merged.
PERSIST: If the parent entity is persisted into the persistence context, the related entity will also be persisted.
REFRESH: If the parent entity is refreshed in the current persistence context, the related entity will also be refreshed.
REMOVE: If the parent entity is removed from the current persistence context, the related entity will also be removed.

Cascade delete relationships are specified using the cascade=REMOVE element specification for
@OneToOne and @OneToMany relationships.

For example:

@OneToMany(cascade=REMOVE, mappedBy="customer")
public Set<Order> getOrders() { return orders; }

Orphan Removal in Relationships

When a target entity in one-to-one or one-to-many relationship is removed from the relationship, it is often desirable to cascade the remove operation to the target entity. Such target entities are considered “orphans,” and the orphanRemoval attribute can be used to specify that orphaned entities should be removed. For example, if an order has many order items and one of them is removed from the order, the removed order item is considered an orphan. If orphanRemoval is set to true, the order item entity will be deleted when the order item is removed from the order.
The orphanRemoval attribute in @OneToMany and @OneToOne takes a Boolean value and is by default false.

The following example will cascade the remove operation to the orphaned order entity when the customer entity is deleted:

@OneToMany(mappedBy="customer", orphanRemoval="true")
public List<Order> getOrders() { ... }

Fetch Details

The FetchType defines when Hibernate gets the related entities from the database, and it is one of the crucial elements for a fast persistence tier. In general, you want to fetch the entities you use in your business tier as efficiently as possible. But that’s not that easy. You either get all relationships with one query or you fetch only the root entity and initialize the relationships as soon as you need them.

FetchType.LAZY

When you started with Hibernate, you most likely either didn’t know about FetchTypes or you were told to always use FetchType.LAZY. In general, that’s a good recommendation. But what does it exactly mean? And what is the default if you don’t define the FetchType?

The default depends on the cardinality of the relationship. All to-one relationships use FetchType.EAGER and all to-many relationships FetchType.LAZY.

Even the best default doesn’t fit for all use cases, and you sometimes want to change it. You can do this by providing your preferred FetchType to the relationship annotation as you can see in the following code snippet.

@Entity
@Table(name = "orders")
public class Order implements Serializable {

  @OneToMany(mappedBy = "order", fetch = FetchType.EAGER)
  private Set<OrderItem> items = new HashSet<OrderItem>();


}

FetchType.EAGER

The FetchType.EAGER tells Hibernate to get all elements of a relationship when selecting the root entity. As explained earlier, this is the default for to-one relationships, and you can see it in the following code snippets.

I use the default FetchType (EAGER) for the many-to-one relationship between the OrderItem and Product entity.

@Entity
public class OrderItem implements Serializable
{
   @ManyToOne
   private Product product;  
}

When an OrderItem entity is fetched from the database, Hibernate will also get the related Product entity.

This seems to be very useful in the beginning. Joining the required entities and getting all of them in one query is very efficient.

But keep in mind, that Hibernate will ALWAYS fetch the Product entity for your OrderItem, even if you don’t use it in your business code. If the related entity isn’t too big, this is not an issue for to-one relationships. But it will most likely slow down your application if you use it for a to-many relationship that you don’t need for your use case. Hibernate then has to fetch tens or even hundreds of additional entities which creates a significant overhead.